package com.ytt.core.service.service.student;


import com.ytt.core.model.common.PageDataDTO;
import com.ytt.core.model.common.SimpleDataDTO;
import com.ytt.core.model.student.StudentDto;
import com.ytt.core.model.student.StudentEditDto;
import com.ytt.core.model.student.StudentRegisterDto;
import com.ytt.core.model.user.UserDto;
import com.ytt.core.service.entity.role.Role;
import com.ytt.core.service.entity.student.Student;
import com.ytt.core.service.entity.user.User;
import com.ytt.core.service.exception.NoSuchDataException;
import com.ytt.core.service.mapper.student.StudentMapper;
import com.ytt.core.service.mapper.user.UserMapper;
import com.ytt.core.service.repository.RoleRepository;
import com.ytt.core.service.repository.StudentRepository;
import com.ytt.core.service.repository.UserRepository;
import com.ytt.core.service.service.ProposalQueryParam;
import com.ytt.core.service.utils.BaseUtil;
import com.ytt.core.service.utils.PageDataUtil;
import com.ytt.core.util.jpa.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service("studentService")
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class StudentImpl implements  StudentService {
    private static final String PASS_PLACE_HOLDER = "$pWd$(C%#*(78))!<>";
    private final StudentMapper studentMapper;

    private final StudentRepository studentRepository;

    private  final UserMapper userMapper;

    private  final UserRepository userRepository;

    private  final RoleRepository roleRepository;
    @Autowired
    public StudentImpl(StudentMapper studentMapper, StudentRepository studentRepository, UserMapper userMapper, UserRepository userRepository, RoleRepository roleRepository) {
        this.studentMapper = studentMapper;
        this.studentRepository = studentRepository;
        this.userMapper = userMapper;
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
    }

    @Override
    public StudentDto findById(String id) {

        Student notification = this.studentRepository.findById(Long.valueOf(id)).orElseThrow(() -> new NoSuchDataException(id));

        return this.studentMapper.toDTO(notification);
    }

    @Override
    public List<StudentDto> findAll(String sort, ProposalQueryParam param) {

        List<Sort.Order> orders = PageHelper.toSortOrderList(sort);
        Sort sort1 = Sort.by(orders);
        List<Student> notifications = this.studentRepository.findAll(
                          BaseUtil.<Student>getBuilder(param).build(),sort1);
        return notifications.stream().map(this.studentMapper::toDTO).collect(Collectors.toList()).stream().peek(n->{
            UserDto userDto=n.getUser();
            //设置用户的密码 防止密码返回真实的数据泄露
            userDto.setPassword(PASS_PLACE_HOLDER);
            n.setUser(userDto);
        }).collect(Collectors.toList());
    }

    @Override
    public PageDataDTO<StudentDto> findOnePage(Integer page, Integer size, String sort, ProposalQueryParam param) {
        Page<Student> notificationPage = this.studentRepository.findAll(
                BaseUtil.<Student>getBuilder(param).build(), PageHelper.generatePageRequest(page, size, sort));
        List<StudentDto> notificationDTOList = notificationPage.getContent().stream().map(this.studentMapper::toDTO)
                .collect(Collectors.toList()).stream().peek(n->{
            UserDto userDto=n.getUser();
             //设置用户的密码 防止密码返回真实的数据泄露
            userDto.setPassword(PASS_PLACE_HOLDER);
            n.setUser(userDto);
                }).collect(Collectors.toList());
        return PageDataUtil.toPageData(notificationPage, notificationDTOList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public StudentDto create(StudentEditDto saveDTO) {
        User user=new User();
        userMapper.updateEntity(saveDTO,user);
        user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));
        //设置学生的角色
        Optional<Role> role= roleRepository.findById(3L);
        if(role.isPresent()) {
            Set<Role> roles=new HashSet<>();
            roles.add(role.get());
            user.setRoles(roles);
        }
        user = this.userRepository.save(user);


        Student entity = new Student();
        this.studentMapper.updateEntity(saveDTO, entity);
        entity.setUser(user);
        entity = this.studentRepository.save(entity);

        StudentDto studentDto=  this.studentMapper.toDTO(entity);
        UserDto userDto=this.userMapper.toDTO(user);
        //设置用户的密码 防止密码返回真实的数据泄露
        userDto.setPassword(PASS_PLACE_HOLDER);
        studentDto.setUser(userDto);
        return studentDto;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public StudentDto register(StudentRegisterDto studentRegisterDto) {
        User user=userMapper.toEntity(studentRegisterDto);
        user.setPassword(this.setPassword(user.getPassword()));
        //设置学生的角色
        setStudentRole(user);
        user = this.userRepository.save(user);
        Student entity = new Student();
        this.studentMapper.updateRegisterEntity(studentRegisterDto, entity);
        entity.setUser(user);
        entity = this.studentRepository.save(entity);

        StudentDto studentDto=  this.studentMapper.toDTO(entity);
        UserDto userDto=this.userMapper.toDTO(user);
        //设置用户的密码 防止密码返回真实的数据泄露
        userDto.setPassword(PASS_PLACE_HOLDER);
        studentDto.setUser(userDto);
        return  studentDto;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public StudentDto update(String id, StudentEditDto saveDTO) {

        Optional<Student> optional = this.studentRepository.findById(Long.valueOf(id));
        Student entity = optional.orElseThrow(() -> new NoSuchDataException(id));

        this.studentMapper.updateEntity(saveDTO, entity);
        entity = this.studentRepository.saveAndFlush(entity);

        Optional<User> optionalUser = this.userRepository.findById(entity.getUser().getId());
        User user = optionalUser.orElseThrow(() -> new NoSuchDataException(id));
        saveDTO.setId(String.valueOf(entity.getUser().getId()));
        userMapper.updateEntity(saveDTO,user);
        String oldPwd = optionalUser.get().getPassword();
        if (!PASS_PLACE_HOLDER.equals(saveDTO.getPassword())) {
            user.setPassword(new BCryptPasswordEncoder().encode(saveDTO.getPassword()));
        } else {
            user.setPassword(oldPwd);
        }
        user = this.userRepository.saveAndFlush(user);

        StudentDto studentDto=  this.studentMapper.toDTO(entity);
        UserDto userDto=this.userMapper.toDTO(user);
        //设置用户的密码 防止密码返回真实的数据泄露
        userDto.setPassword(PASS_PLACE_HOLDER);
        studentDto.setUser(userDto);
        return studentDto;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(String id) {
        Student entity = this.studentRepository.findById(Long.valueOf(id)).orElseThrow(() -> new NoSuchDataException(id));
        this.studentRepository.delete(entity);

        User user = this.userRepository.findById(entity.getUser().getId()).orElseThrow(() -> new NoSuchDataException(String.valueOf(entity.getUser().getId())));
        //解锁用户角色
        user.getRoles().forEach(role -> role.getUsers().remove(user));
        this.userRepository.delete(user);
    }

    @Override
    public SimpleDataDTO<Boolean> checkStudentIdAvailability(String id, String studentId) {
        String foundUserId = this.findByStudentId(studentId);
        if (foundUserId == null) {
            return new SimpleDataDTO<>(true);
        } else {
            boolean rtn = id != null && id.equalsIgnoreCase(foundUserId);
            return new SimpleDataDTO<>(rtn);
        }
    }

    @Override
    public String findByStudentId(String studentId) {
        Long id = studentRepository.findByStudent_id(studentId);
        if (id == null) {
            return  null;
        } else {
            return String.valueOf(id);
        }
    }

   public  String  setPassword(String password){
            return  new BCryptPasswordEncoder().encode(password);
    }
    public  void setStudentRole(User user){
        Optional<Role> role= roleRepository.findById(3L);
        if(role.isPresent()) {
            Set<Role> roles=new HashSet<>();
            roles.add(role.get());
            user.setRoles(roles);
        }
    }
}
